package com.epam.task.thread;

import org.apache.log4j.Logger;
import java.util.ResourceBundle;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;

public class CallCenter {
    public static final Logger log = Logger.getLogger(CallCenter.class);
    public static final String PROPERTIES_FILE =
            "resources/operator";
    public static final int DEFAULT_POOL_SIZE = 10;
    /**
     * single instance
     */
    private static CallCenter instance;
    /**
     * free operators queue
     */
    private BlockingQueue<Operator> operatorsQueue;

    private CallCenter(String name, int staffSize)
            throws ClassNotFoundException {
        Class.forName(name);
        operatorsQueue
                = new ArrayBlockingQueue<Operator>(staffSize);
        for (int i = 0; i < staffSize; i++) {
            Operator operator = new Operator(name);
            operatorsQueue.offer(operator);
        }
    }

    public static void init(){
        if (instance == null) {
            ResourceBundle rb = ResourceBundle.getBundle(
                    PROPERTIES_FILE);
            String name = rb.getString("name");
            String staffSizeStr = rb.getString("staffSize");
            int staffSize = (staffSizeStr != null) ?
                    Integer.parseInt(staffSizeStr) : DEFAULT_POOL_SIZE;
            try {
                instance = new CallCenter(name, staffSize);
            } catch (ClassNotFoundException e) {
                throw new RuntimeException(e);
            }
        }
    }

    public static void dispose() {
        if (instance != null) {
            instance.clearOperatorQueue();
            instance = null;
        }
    }

    public static CallCenter getInstance() {
        return instance;
    }

    public Operator takeOperator() {
        Operator operator = null;
        try {
            operator = operatorsQueue.take();
        } catch (InterruptedException e) {
            //"Free operator waiting interrupted.
            // Returned `null` operator", e
        }
        return operator;
    }

    public void releaseOperator(Operator operator) {
        if (!operator.isClosed()) {
            if (!operatorsQueue.offer(operator)) {
                //"Operator not added. Possible `leakage` of
                // operators"
            }
        } else {
            //"Trying to release closed operator. Possible
            // `leakage` of operators"
        }
    }

    private void clearOperatorQueue() {
        Operator operator;
        while ((operator = operatorsQueue.poll()) != null) {
            if (!operator.getAutoCommit()) {
                operator.commit();
            }
            operator.close();
        }
    }
}
